﻿using Library.Core.Application.IInfrastructure;
using Library.Core.Infrastructure.Common;
using Library.Core.Infrastructure.EntityFrameworkDataAccess;
using Library.Core.Infrastructure.EntityFrameworkDataAcceSynthetic.Extension;
using Microsoft.EntityFrameworkCore;
using Synthesize.BaseSet.Domain.Aggregation.Dtos.Authority.Menu;
using Synthesize.BaseSet.Domain.Aggregation.Entity.Authority;
using Synthesize.BaseSet.Domain.Repository.Authority;
using Synthesize.Infrastructure.PersistentObjects.Authority;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Synthesize.Infrastructure.Repository.Authority
{
    /// <summary>
    ///菜单基础类
    /// </summary>
    public class MenuRepository : RepositoryBase<MenuInfoEntity, MenuInfo>, IMenuRepository
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="currentUserInfo"></param>
        /// <param name="dbContext"></param>
        public MenuRepository(ICurrentUserInfo currentUserInfo, IEFContext dbContext) : base(currentUserInfo, dbContext)
        {

        }

        /// <summary>
        /// 根据条件获取菜单信息
        /// </summary>
        /// <param name="specification"></param>
        /// <param name="readOnly"></param>
        /// <returns></returns>
        public async Task<List<GetMenuDetailListOutDto>> GetMenuList(Expression<Func<MenuInfoEntity, bool>> specification, bool readOnly)
        {

            var result = new List<GetMenuDetailListOutDto>();

            var menuList = await GetAll(readOnly: readOnly)
                        .Where(specification.ReplaceParameter<MenuInfoEntity, MenuInfo>())
                        .OrderBy(x => x.Sort)
                        .ToListAsync();
            if (menuList.Any())
            {
                //获取菜单权限信息
                var menuIdList = menuList.Select(x => x.Id);
                var menuPermissionList = await GetAll<MenuPermissionInfo>(readOnly: readOnly)
                            .Where(x => menuIdList.Contains(x.MenuId))
                            .ToListAsync();
                result = menuList.MapList<MenuInfo, GetMenuDetailListOutDto>();

                foreach (var item in result)
                {
                    var menuPermissions = menuPermissionList.Where(x => x.MenuId == item.Id).ToList();
                    if (menuPermissions.Any())
                    {
                        item.MenuPermissionList = menuPermissions.MapList<MenuPermissionInfo, MenuPermissionInfoEntity>();
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// 根据平台获取菜单信息【角色Id条件，作用于left join】
        /// </summary>
        /// <param name="input"></param>
        /// <param name="readOnly"></param>
        /// <returns></returns>
        public async Task<List<GetMenuTreeByPlatformOutDto>> GetMenuListByPlatform(GetMenuListByPlatformInDto input, bool readOnly)
        {
            var menuQuery = GetAll(readOnly: readOnly)
                    .Where(x => x.Platform == input.Platform)
                    .OrderBy(x => x.Sort);
            var roleMenuQuery = GetAll<RoleMenuRe>(readOnly: readOnly)
                    .Where(x => input.RoleIdList.Contains(x.RoleId));

            var result = await menuQuery
                    .GroupJoin(roleMenuQuery, mq => mq.Id, rmq => rmq.MenuId, (mq, rmq) => new { mq, rmq })
                    .SelectMany(x => x.rmq.DefaultIfEmpty(), (x, r) => new { x.mq, r })
                    .Select(x => new GetMenuTreeByPlatformOutDto
                    {
                        Id = x.mq.Id,
                        ParentId = x.mq.ParentId,
                        Title = x.mq.Title,
                        MenuType = x.mq.MenuType,
                        HasAuth = x.r != null ? true : false,
                    }).ToListAsync();

            if (result.Any())
            {
                //获取菜单权限信息
                var menuIdList = result.Select(x => x.Id);

                var menuPermissionList = await GetAll<MenuPermissionInfo>(readOnly: readOnly)
                            .Where(x => menuIdList.Contains(x.MenuId))
                            .Select(x => new GetRoleMenuPermissionOutDto
                            {
                                Id = x.Id,
                                MenuId = x.MenuId,
                                Name = x.Name,
                                Code = x.Code,
                            }).ToListAsync();

                foreach (var item in result)
                {
                    item.MenuPermissionList = menuPermissionList.Where(x => x.MenuId == item.Id).ToList();
                }
            }
            return result;
        }

        /// <summary>
        /// 根据角色获取菜单信息[角色Id条件，作用于 join]
        /// </summary>
        /// <param name="input"></param>
        /// <param name="readOnly"></param>
        /// <returns></returns>
        public async Task<List<MenuInfoEntity>> GetMenuListByRole(GetMenuListByRoleInDto input, bool readOnly)
        {
            var result = new List<MenuInfoEntity>();

            var menuQuery = GetAll(readOnly: readOnly)
                    .Where(x => x.Platform == input.Platform)
                    .OrderBy(x => x.Sort);

            var roleMenuQuery = GetAll<RoleMenuRe>(readOnly: readOnly)
                    .Where(x => input.RoleIdList.Contains(x.RoleId))
                    .GroupBy(x => x.MenuId)
                    .Select(x => new
                    {
                        MenuId = x.Key
                    });

            var menuList = await menuQuery
                    .Join(roleMenuQuery, mq => mq.Id, rmq => rmq.MenuId, (mq, rmq) => new { mq, rmq })
                    .Select(x =>x.mq).ToListAsync();

            if (menuList.Any())
            {
                result = menuList.MapList<MenuInfo, MenuInfoEntity>();
            }

            return result;
        }

        /// <summary>
        /// 获取角色对应可操作权限信息
        /// </summary>
        /// <param name="input"></param>
        /// <param name="readOnly"></param>
        /// <returns></returns>
        public async Task<List<GetRoleMenuPermissionOutDto>> GetMenuPermissionListByRole(GetMenuPermissionListByRoleInDto input, bool readOnly)
        {
            var roleMenuPermissionQuery = GetAll<RoleMenuPermissionRe>(readOnly: readOnly)
                        .Where(x =>input.RoleIdList.Contains(x.RoleId));
            var menuPermissionQuery = GetAll<MenuPermissionInfo>(readOnly: readOnly);

            var menuPermissionList = await roleMenuPermissionQuery
                        .Join(menuPermissionQuery, rmp => rmp.MenuPermissionId, mp => mp.Id, (rmp, mp) => new { rmp, mp })
                        .Select(x => new GetRoleMenuPermissionOutDto
                        {
                            Id = x.mp.Id,
                            MenuId = x.mp.MenuId,
                            Name = x.mp.Name,
                            Code = x.mp.Code,
                        }).ToListAsync();

            return menuPermissionList;
        }
    }
}
